package com.zshan.clinic.web.filter;

import com.zshan.clinic.common.response.RestResp;
import com.zshan.clinic.common.util.attack.SqlCleanUtil;
import com.zshan.clinic.common.util.attack.XssCleanUtil;
import com.zshan.clinic.common.util.ip.IpUtil;
import com.zshan.clinic.common.util.json.JsonUtil;
import com.zshan.clinic.common.util.limit.LuaRateLimiter;
import com.zshan.clinic.web.constant.WebConstant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;

@Configuration
@Slf4j
public class CustomFilter implements Filter {


    @Autowired
    private LuaRateLimiter rateLimiter;

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        String requestUri = httpServletRequest.getRequestURI();
        //1.白名单校验
        if(WebConstant.isFilterAllow(requestUri)){
            filterChain.doFilter(httpServletRequest,servletResponse);
            return;
        }
        //2.添加ip
        String requestIp = IpUtil.getIpAdrress(httpServletRequest);
        CustomHttpServletRequest request = new CustomHttpServletRequest(httpServletRequest);
        request.addHeader("ip",requestIp);
        //3.限流控制
        boolean allowed = rateLimiter.tryAcquire(requestIp,requestUri);
        if (!allowed) {
            log.info(">>>>>>>>>请求频繁>>>>>>>>>>>>,请求IP:{},请求地址:{}",requestIp,requestUri);
            failHandle(servletResponse,RestResp.SYSTEM_FAIL("请求频繁，请稍后再试"));
            return;
        }
        //4.获取get或者post中的请求参数其中get方法拼接在url后边，post参数放到requestbody中;并且转换成Map<String, Object> params
        Map<String, Object> params = request.getRequestParams(httpServletRequest);
        //5.对请求的参数进行sql注入和xss攻击校验
        boolean isSql = SqlCleanUtil.inject(params);
        if(!isSql){
            log.info(">>>>>>>>>存在非法字符串>>>>>>>>>>>>,请求IP:{},请求地址:{},请求参数:{}",requestIp,requestUri,params);
            failHandle(servletResponse,RestResp.SYSTEM_FAIL("非法请求"));
            return;
        }
        params = XssCleanUtil.cleanMapXSS(params);
        //6.重新设置请求参数
        request.setParams(params);
        //7.放行
        filterChain.doFilter(request,servletResponse);
    }



    private void failHandle(ServletResponse response,RestResp restResp){
        try {
            HttpServletResponse httpResponse = (HttpServletResponse) response;
            httpResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
            httpResponse.setCharacterEncoding("UTF-8");
            httpResponse.setStatus(HttpStatus.OK.value());
            PrintWriter writer = httpResponse.getWriter();
            writer.write(JsonUtil.obj2Json(restResp));
            writer.flush();
            writer.close();
        }catch (Exception e){

        }
    }
}
